from typing import Optional, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, or_, and_
from fastapi import HTTPException, status

from modules.system.models.dict_item import Dictionary
from modules.system.models.dict import DictType
from modules.system.schemas.dict_item_schemas import DictItemCreate, DictItemUpdate
from modules.system.params.dict_item_params import DictItemQuery
from modules.system.curd.dict_item_curd import dict_item_dao
from utils.query_builder import build_select_stmt
from core.pagination import paging_data, _CustomPageParams


class DictItemService:
    @staticmethod
    async def get_item_by_id(db: AsyncSession, item_id: int) -> Optional[Dictionary]:
        return await dict_item_dao.get_by_id(db, item_id)

    @staticmethod
    async def get_item_by_key_and_type(db: AsyncSession, dict_key: str, dict_type: str) -> Optional[Dictionary]:
        return await dict_item_dao.get_by_key_and_type(db, dict_key, dict_type)

    @staticmethod
    async def get_items_with_pagination(db: AsyncSession, query_params: DictItemQuery) -> Dict[str, Any]:
        # 统一查询构建与分页封装
        stmt = build_select_stmt(
            Dictionary,
            query_params,
            text_like_fields={"dict_key", "dict_value", "category", "options"},
            keyword_fields={"dict_key", "dict_value", "category", "options"},
        )
        # 精确匹配 dict_type（如果提供）
        if query_params.dict_type:
            stmt = stmt.where(Dictionary.dict_type == query_params.dict_type)
        stmt = stmt.order_by(Dictionary.sort_order.asc(), Dictionary.id.desc())
        params = _CustomPageParams(page=query_params.page, size=query_params.size)
        page_data = await paging_data(db, stmt, params=params)
        page_data["pages"] = page_data.get("total_pages", 0)
        page_data.pop("links", None)
        return page_data

    @staticmethod
    async def create_item(db: AsyncSession, payload: DictItemCreate) -> Dictionary:
        # 先校验类型是否存在
        type_res = await db.execute(select(DictType).where(DictType.type_code == payload.dict_type))
        if not type_res.scalar_one_or_none():
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="字典类型不存在")

        # 唯一性校验：同类型下 dict_key 唯一
        exist_item = await DictItemService.get_item_by_key_and_type(db, payload.dict_key, payload.dict_type)
        if exist_item:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="同类型下字典键已存在")

        obj = await dict_item_dao.create(db, payload)
        await db.commit()
        await db.refresh(obj)
        return obj

    @staticmethod
    async def update_item(db: AsyncSession, item_id: int, payload: DictItemUpdate) -> Dictionary:
        obj = await DictItemService.get_item_by_id(db, item_id)
        if not obj:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="字典项不存在")

        # 如果变更 dict_type，需要校验新类型是否存在
        if payload.dict_type and payload.dict_type != obj.dict_type:
            type_res = await db.execute(select(DictType).where(DictType.type_code == payload.dict_type))
            if not type_res.scalar_one_or_none():
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="字典类型不存在")

        # 唯一性校验：同类型下 dict_key 不能与其他项重复
        new_type = payload.dict_type if payload.dict_type is not None else obj.dict_type
        new_key = payload.dict_key if payload.dict_key is not None else obj.dict_key
        exist_item = await DictItemService.get_item_by_key_and_type(db, new_key, new_type)
        if exist_item and exist_item.id != obj.id:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="同类型下字典键已存在")

        # 使用仓储更新（仓储已按模型字段赋值）
        obj = await dict_item_dao.update(db, item_id, payload)
        await db.commit()
        if obj:
            await db.refresh(obj)
        return obj

    @staticmethod
    async def delete_item(db: AsyncSession, item_id: int) -> None:
        obj = await DictItemService.get_item_by_id(db, item_id)
        if not obj:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="字典项不存在")
        await dict_item_dao.delete(db, item_id)
        await db.commit()